package com.north.light.libtencentbugly

import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.os.Build
import android.os.Process
import android.text.TextUtils
import java.io.Serializable

/**
 * Created by lzt
 * time 2020/10/27
 * 描述：进程管理类
 */
open class LibBuglyProcessUtil : Serializable {
    private var currentProcessName: String? = null

    companion object {
        @JvmStatic
        fun getInstance(): LibBuglyProcessUtil {
            return SingleHolder.mInstance
        }
    }

    object SingleHolder {
        val mInstance = LibBuglyProcessUtil()
    }

    /**
     * @return 当前进程名
     */
    fun getCurrentProcessName(context: Context): String? {
        if (!TextUtils.isEmpty(currentProcessName)) {
            return currentProcessName
        }

        //1)通过Application的API获取当前进程名
        currentProcessName = currentProcessNameByApplication
        if (!TextUtils.isEmpty(currentProcessName)) {
            return currentProcessName
        }

        //2)通过反射ActivityThread获取当前进程名
        currentProcessName = currentProcessNameByActivityThread
        if (!TextUtils.isEmpty(currentProcessName)) {
            return currentProcessName
        }

        //3)通过ActivityManager获取当前进程名
        currentProcessName = getCurrentProcessNameByActivityManager(context)

        return currentProcessName
    }


    /**
     * 通过Application新的API获取进程名，无需反射，无需IPC，效率最高。
     */
    val currentProcessNameByApplication: String?
        get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            Application.getProcessName()
        } else null

    /**
     * 通过反射ActivityThread获取进程名，避免了ipc
     */
    val currentProcessNameByActivityThread: String?
        get() {
            var processName: String? = null
            try {
                val declaredMethod = Class.forName("android.app.ActivityThread", false, Application::class.java.classLoader)
                    .getDeclaredMethod(
                        "currentProcessName",
                        *arrayOfNulls<Class<*>>(0) as Array<Class<*>>)
                declaredMethod.isAccessible = true
                val invoke = declaredMethod.invoke(null, *arrayOfNulls(0))
                if (invoke is String) {
                    processName = invoke
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            }

            return processName
        }

    /**
     * 通过ActivityManager 获取进程名，需要IPC通信
     */
    fun getCurrentProcessNameByActivityManager(context: Context): String? {
        val pid = Process.myPid()
        val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val runningAppList = am.runningAppProcesses
        if (runningAppList != null) {
            for (processInfo in runningAppList) {
                if (processInfo.pid == pid) {
                    return processInfo.processName
                }
            }
        }
        return null
    }

}
